#ifndef A8_SYSUTILS_H
#define A8_SYSUTILS_H

#include <string>
#include <time.h>
#ifdef WIN32
#include <windows.h>
#include <WinSock2.h>
#else
#include <sys/time.h>
#endif
#include <limits.h>

#ifdef WIN32
static int gettimeofday(struct timeval *tp, void *tzp)
{
    time_t clock;
    struct tm tm;
    SYSTEMTIME wtm;
    GetLocalTime(&wtm);
    tm.tm_year     = wtm.wYear - 1900;
    tm.tm_mon     = wtm.wMonth - 1;
    tm.tm_mday     = wtm.wDay;
    tm.tm_hour     = wtm.wHour;
    tm.tm_min     = wtm.wMinute;
    tm.tm_sec     = wtm.wSecond;
    tm. tm_isdst    = -1;
    clock = mktime(&tm);
    tp->tv_sec = clock;
    tp->tv_usec = wtm.wMilliseconds * 1000;
    return (0);
}
#endif

static unsigned long long getMilliSecond()
{
	struct timeval tv;
	gettimeofday(&tv, NULL);
	unsigned long long time = tv.tv_usec;
	time /= 1000;
	time += (tv.tv_sec * 1000);
	return time;	
}

static unsigned long XGetTickCount()
{
#ifdef WIN32
    return GetTickCount();
#else
	struct timespec ts;
	clock_gettime(CLOCK_MONOTONIC,&ts);    
	return (ts.tv_sec*1000 + ts.tv_nsec/(1000*1000));
#endif
}

namespace a8
{
	template <class T>
	inline int arraysize(T& array)
	{
		return (sizeof(array) / sizeof(array[0]));
	}

	template <typename T>
	inline int getvalidbytes(T& val)
	{
		long long absval = val < 0 ? -val : val;
		if(absval <= 0xFF){
			return 1;
		}else if(absval <= 0xFFFF){
			return 2;
		}else if(absval <= 0xFFFFFF){
			return 3;
		}else if(absval <= 0xFFFFFFFF){
			return 4;
		}else if(absval <= 0xFFFFFFFFFF){
			return 5;
		}else if(absval <= 0xFFFFFFFFFFFF){
			return 6;
		}else if(absval <= 0xFFFFFFFFFFFFFF){
			return 7;
		}else{
			return 8;
		}
	}

	inline static int hashint(int val)
	{
		return val;
	}

	// AP Hash Function
	inline static int hashstring(const char* str)
	{
		unsigned int hash = 0;
		int i;

		for (i=0; *str; i++){
			if ((i & 1) == 0){
				hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
			}else{
				hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
			}
		}
		return (hash & 0x7FFFFFFF);
	}

	inline static int hashstring(const std::string& str)
	{
		return hashstring(str.c_str());
	}

	static int cmpint_asc(const void *a, const void *b)
	{
		return *(int*)a - *(int*)b;
	}

	static int cmpint_desc(const void *a, const void *b)
	{
		return *(int*)b - *(int*)a;
	}

	template <typename T1, 
			  typename T2>
	bool BeOverflow(const T1& oldval, const T2& addval)
	{
		return oldval + addval < oldval;
	}

	template <typename T>
	T GetNumberMaxLimit(const T& val)
	{
		return (T)~((T)0) < 0 ? ~((T)1 << (8 * sizeof(T)) - 1): ~((T)0);
	}

	static bool IsSameMonth(time_t t1, time_t t2)
	{
		struct tm tm1, tm2;
		memset(&tm1, 0, sizeof(tm1));
		memset(&tm2, 0, sizeof(tm2));
#ifdef WIN32
		localtime_s(&tm1, &t1);
		localtime_s(&tm2, &t2);
#else
		localtime_r(&t1, &tm1);
		localtime_r(&t2, &tm2);
#endif
		return tm1.tm_year == tm2.tm_year && tm1.tm_mon == tm2.tm_mon;
	}

	static int GetMonthDays(time_t time_now)
	{
		int monthdays = 1;

		while(true){
			struct tm tm_now;
			memset(&tm_now, 0, sizeof(tm_now));
#ifdef WIN32
			localtime_s(&tm_now, &time_now);
#else
			localtime_r(&time_now, &tm_now);
#endif
			if(tm_now.tm_mday < monthdays){
				break;
			}
			monthdays = tm_now.tm_mday;
			time_now += 3600 * 24;
		}
		
		return monthdays;
	}

	template <typename T>
	T Get(std::vector<T> &vector_t, unsigned int idx, const T& defval)
	{
		if(idx < vector_t.size()){
			return vector_t[idx];
		}else{
			return defval;
		}
	}
}

static std::string ExtractFilePath(const char * szPath)
{
	if (szPath && *szPath){
		const char *p1 = strrchr(szPath, '\\');
		const char *p2 = strrchr(szPath, '/');
		if (!p1 && !p2)
			return std::string(szPath);
		else
			return std::string(szPath, p1 > p2 ? ++p1 : ++p2);
	}else{
		return std::string("");
	}
}

static std::string GetAppPath()
{
#ifdef WIN32
	char buf[MAX_PATH] = {0};
	GetModuleFileNameA(NULL, buf, MAX_PATH);
	return ExtractFilePath(buf);
#else
	return "";
#endif
}

#endif
